from socket import *
import threading
import select

class RccsCommunicatorObj:
    def __init__(self, host, port, signal=None, buff_size=1024, retry_time=10):
        self.res = ''
        self.buff_size = buff_size
        self.retry_time = retry_time
        self.addr = (host, port)
        self.tcpCliSock = socket(AF_INET, SOCK_STREAM)
        # self.tcpCliSock.settimeout(5)
        # 创建线程锁，防止主线程socket被close了，子线程还在recv而引发的异常
        self.socket_lock = threading.Lock()
        self.start_recv()
        self.connect()
        self.signal = signal

    def read_thread_method(self):
        while True:
            if not self.tcpCliSock:  # 如果socket关闭，退出
                break
            # 使用select监听客户端（这里客户端需要不停接收服务端的数据，所以监听客户端）
            # 第一个参数是要监听读事件列表，因为是客户端，我们只监听创建的一个socket就ok
            # 第二个参数是要监听写事件列表，
            # 第三个参数是要监听异常事件列表，
            # 最后一个参数是监听超时时间，默认永不超时。如果设置了超时时间，过了超时时间线程就不会阻塞在select方法上，会继续向下执行
            # 返回参数 分别对应监听到的读事件列表，写事件列表，异常事件列表
            rs, _, _ = select.select([self.tcpCliSock], [], [], 1000)
            for r in rs:  # 我们这里只监听读事件，所以只管读的返回句柄数组
                self.socket_lock.acquire()  # 在读取之前先加锁，锁定socket对象（sock是主线程和子线程的共享资源，锁定了sock就能保证子线程在使用sock时，主线程无法对sock进行操作）

                if not self.tcpCliSock:  # 这里需要判断下，因为有可能在select后到加锁之间socket被关闭了
                    self.socket_lock.release()
                    break

                data = r.recv(1024)  # 读数据，按自己的方式读

                self.socket_lock.release()  # 读取完成之后解锁，释放资源

                if not data:
                    # print('server close')
                    pass
                else:
                    self.__read_recv_data(data.decode('utf-8'))
                    # self.signal.emit(data.decode("utf-8"))

    def start_recv(self):
        # 创建一个线程去读取数据
        read_thread = threading.Thread(target=self.read_thread_method)
        read_thread.setDaemon(True)
        read_thread.start()

    def connect(self):
        try:
            print('开始连接RCCS')
            self.tcpCliSock.connect(self.addr)
            print('已连接RCCS')
            # self.init()
        except ConnectionRefusedError:
            pass
            # self.connect()

    def close(self):
        self.tcpCliSock.close()

    def init(self, station_id=1, t=0):
        print('发送S1Init')
        command = f'S{str(station_id)}Init'
        self.send(command)
        # if t > self.retry_time:
        #     return '超过最大尝试次数，请检查RCCS系统！'
        #
        # if self.res == f'S{str(station_id)}InitOk':
        #     pass
        # else:
        #     # self.connect()
        #     self.init(station_id, t + 1)

    def send(self, msg, wati_request=False):
        print(f'发送数据: {msg}')
        try:
            self.tcpCliSock.send(msg.encode())
            if wati_request:
                self.res = self.tcpCliSock.recv(self.buff_size)
                self.__read_recv_data(self.res.decode('utf-8'))
        except:
            self.connect()

    def __read_recv_data(self, data):
        print(f'receive data: {data}')
        if data == 'S1InitOK':
            pass
        elif data.startswith('S1Code'):
            step = 'get_bar_code'
            codes = data.split(':')[1].split(',')
            return_codes = {}
            for code in codes:
                index = code.split('=')[0].replace('SN', '')
                return_codes[index] = code.split('=')[1].strip()
            if self.signal:
                self.signal.emit(step, return_codes)
            self.send('S1CodeOK')
        elif data.__contains__('S1RestartOK'):
            step = 'write'
            if self.signal:
                self.signal.emit(step, {})
        elif data == 'S1ResultOK':
            pass
        else:
            pass
